package com.bocloud.cmp.service.utils;

import java.net.URLDecoder;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;

import com.bocloud.cmp.dao.CloudServerDao;
import com.bocloud.cmp.dao.ClusterDao;
import com.bocloud.cmp.dao.DataStoreDao;
import com.bocloud.cmp.dao.HostSystemDao;
import com.bocloud.cmp.dao.NetworkCardDao;
import com.bocloud.cmp.dao.NetworkDao;
import com.bocloud.cmp.dao.NetworkHostDao;
import com.bocloud.cmp.dao.PortGroupDao;
import com.bocloud.cmp.dao.SnapshotDao;
import com.bocloud.cmp.dao.StoreHostDao;
import com.bocloud.cmp.entity.resource.CloudServer;
import com.bocloud.cmp.entity.resource.Cluster;
import com.bocloud.cmp.entity.resource.DataStore;
import com.bocloud.cmp.entity.resource.HostSystem;
import com.bocloud.cmp.entity.resource.Network;
import com.bocloud.cmp.entity.resource.NetworkCard;
import com.bocloud.cmp.entity.resource.NetworkHost;
import com.bocloud.cmp.entity.resource.PortGroup;
import com.bocloud.cmp.entity.resource.Snapshot;
import com.bocloud.cmp.entity.resource.StoreHost;
import com.bocloud.cmp.enums.VMStatus;
import com.bocloud.cmp.model.HostSystemBean;
import com.bocloud.cmp.model.SnapshotBean;
import com.bocloud.cmp.model.VMBean;
import com.bocloud.common.utils.ListTool;
import com.google.common.collect.Maps;

public class SyncVmwareUtils {

	private CloudServerDao cloudServerDao;
	private DataStoreDao dataStoreDao;
	private HostSystemDao hostSystemDao;
	private SnapshotDao snapshotDao;
	private NetworkDao networkDao;
	private ClusterDao clusterDao;
	private StoreHostDao storeHostDao;
	private NetworkCardDao networkCardDao;
	private PortGroupDao portGroupDao;
	private NetworkHostDao networkHostDao;

	public SyncVmwareUtils() {
		super();
	}

	public SyncVmwareUtils(CloudServerDao cloudServerDao, DataStoreDao dataStoreDao, HostSystemDao hostSystemDao,
			SnapshotDao snapshotDao, NetworkDao networkDao, ClusterDao clusterDao, StoreHostDao storeHostDao,
			NetworkCardDao networkCardDao, PortGroupDao portGroupDao, NetworkHostDao networkHostDao) {
		super();
		this.cloudServerDao = cloudServerDao;
		this.dataStoreDao = dataStoreDao;
		this.hostSystemDao = hostSystemDao;
		this.snapshotDao = snapshotDao;
		this.networkDao = networkDao;
		this.clusterDao = clusterDao;
		this.storeHostDao = storeHostDao;
		this.networkCardDao = networkCardDao;
		this.portGroupDao = portGroupDao;
		this.networkHostDao = networkHostDao;
	}

	/**
	 * 同步集群
	 * 
	 * @param oldCluster
	 * @param newCluster
	 * @param userId
	 * @throws Exception
	 */
	public void mergeCluster(Cluster oldCluster, Cluster newCluster, Long userId) throws Exception {
		oldCluster.setMemUsed(newCluster.getMemUsed());
		oldCluster.setMemTotal(newCluster.getMemTotal());
		oldCluster.setDiskUsed(newCluster.getDiskUsed());
		oldCluster.setDiskTotal(newCluster.getDiskTotal());
		oldCluster.setCpuUsed(newCluster.getCpuUsed());
		oldCluster.setCpuTotal(newCluster.getCpuTotal());
		oldCluster.setCpuCore(newCluster.getCpuCore());
		oldCluster.setHostNum(newCluster.getHostNum());
		oldCluster.setTemplateNum(newCluster.getTemplateNum());
		oldCluster.setVmNum(newCluster.getVmNum());
		oldCluster.setName(newCluster.getName());
		oldCluster.setMenderId(userId);
		clusterDao.update(oldCluster);
	}

	/**
	 * 同步宿主机
	 * 
	 * @param oldHost
	 * @param newHost
	 * @param vendorId
	 * @param vdcId
	 * @param clusterId
	 * @param userId
	 * @param storeMap
	 * @param networkMap
	 * @param groupMap
	 * @throws Exception
	 */
	public void mergeHost(HostSystem oldHost, HostSystem newHost, Long vendorId, Long vdcId, Long clusterId,
			Long userId, Map<String, Long> storeMap, Map<String, Long> networkMap, Map<String, PortGroup> groupMap)
					throws Exception {
		HostSystemBean bean = new HostSystemBean();
		BeanUtils.copyProperties(newHost, bean);
		bean.setId(oldHost.getId());
		BeanUtils.copyProperties(bean, oldHost);
		oldHost.setVdcId(vdcId);
		oldHost.setClusterId(clusterId);
		oldHost.setVendorId(vendorId);
		oldHost.setMenderId(userId);
		hostSystemDao.update(oldHost);
		Long hostId = oldHost.getId();
		// 同步该宿主机和存储的关系
		mergeStoreHost(vendorId, hostId, "PM", newHost.getStores(), storeMap);
		// 同步该宿主机与网络的关系
		mergeNetworkHost(vendorId, hostId, "PM", newHost.getNetworks(), networkMap, groupMap);
		// 同步该宿主机下的网卡
		List<NetworkCard> cards = networkCardDao.listByHost(hostId, "PM");
		syncNetworkCard(cards, newHost.getNetcards(), vendorId, hostId, userId, "PM", groupMap);
	}

	/**
	 * 同步该主机和存储的关系
	 * 
	 * @param vendorId
	 * @param hostId
	 * @param category
	 * @param datastores
	 * @param storeMap
	 * @throws Exception
	 */
	public void mergeStoreHost(Long vendorId, Long hostId, String category, List<String> datastores,
			Map<String, Long> storeMap) throws Exception {
		List<StoreHost> storeHosts = storeHostDao.list(hostId, category);
		Map<String, StoreHost> oldStore = Maps.newHashMap();
		for (StoreHost storeHost : storeHosts) {
			DataStore dataStore = dataStoreDao.query(storeHost.getStoreId());
			oldStore.put(dataStore.getStoreVal(), storeHost);
		}
		if (!ListTool.isEmpty(datastores)) {
			for (String datastore : datastores) {
				if (oldStore.containsKey(datastore)) {
					oldStore.remove(datastore);
					continue;
				}
				if (storeMap.containsKey(datastore)) {
					storeHostDao.save(new StoreHost(storeMap.get(datastore), hostId, vendorId, category));
				}
			}
		}
		for (String dataStore : oldStore.keySet()) {
			storeHostDao.delete(oldStore.get(dataStore));
		}
	}

	/**
	 * 同步宿主机与网络的关系
	 * 
	 * @param vendorId
	 * @param hostId
	 * @param category
	 * @param networks
	 * @param networkMap
	 * @param groupMap
	 * @throws Exception
	 */
	public void mergeNetworkHost(Long vendorId, Long hostId, String category, List<String> networks,
			Map<String, Long> networkMap, Map<String, PortGroup> groupMap) throws Exception {
		List<NetworkHost> networkHosts = networkHostDao.list(hostId, category);
		Map<String, NetworkHost> oldNetwork = Maps.newHashMap();
		Map<String, String> oldGroup = Maps.newHashMap();
		Map<Long, String> idMap = Maps.newHashMap();
		for (NetworkHost networkHost : networkHosts) {
			Network network = networkDao.query(networkHost.getNetworkId());
			if (null == network) {
				continue;
			}
			oldNetwork.put(network.getNetworkVal(), networkHost);
			if ("DVSWITCH".equals(network.getType())) {
				List<PortGroup> groups = portGroupDao.listByNetwork(network.getId());
				for (PortGroup group : groups) {
					oldGroup.put(group.getGroupVal(), network.getNetworkVal());
				}
			}
			idMap.put(network.getId(), network.getNetworkVal());
		}
		if (!ListTool.isEmpty(networks)) {
			for (String network : networks) {
				if (oldNetwork.containsKey(network)) {
					oldNetwork.remove(network);
				} else if (networkMap.containsKey(network)) {
					networkHostDao.save(new NetworkHost(networkMap.get(network), hostId, vendorId, category));
				} else if (oldGroup.containsKey(network) && oldNetwork.containsKey(oldGroup.get(network))) {
					oldNetwork.remove(oldGroup.get(network));
				} else if (groupMap.containsKey(network) && !idMap.containsKey(groupMap.get(network).getNetworkId())) {
					idMap.put(groupMap.get(network).getNetworkId(), network);
					networkHostDao
							.save(new NetworkHost(groupMap.get(network).getNetworkId(), hostId, vendorId, category));
				}
			}
		}
		Iterator<String> iterator = oldNetwork.keySet().iterator();
		while (iterator.hasNext()) {
			networkHostDao.delete(oldNetwork.get(iterator.next()));
		}
	}

	/**
	 * 同步虚拟机
	 * 
	 * @param oldServer
	 * @param newServer
	 * @param hostStatus
	 * @param vendorId
	 * @param hostId
	 * @param userId
	 * @param storeMap
	 * @param networkMap
	 * @param groupMap
	 * @throws Exception
	 */
	public void mergeServer(CloudServer oldServer, CloudServer newServer, String hostStatus, Long vendorId, Long hostId,
			Long userId, Map<String, Long> storeMap, Map<String, Long> networkMap, Map<String, PortGroup> groupMap)
					throws Exception {
		if (VMStatus.BUILDING.name().equals(oldServer.getStatus())) {
			return;
		}
		String managerIp = oldServer.getManagerIp();
		VMBean bean = new VMBean();
		BeanUtils.copyProperties(newServer, bean);
		BeanUtils.copyProperties(bean, oldServer);
		oldServer.setName(URLDecoder.decode(oldServer.getName(), "utf-8"));
		oldServer.setMenderId(userId);
		oldServer.setVendorId(vendorId);
		oldServer.setHostId(hostId);
		if ("UNKNOWN".equals(hostStatus)) {
			if ("poweredOn".equalsIgnoreCase(oldServer.getStatus())) {
				oldServer.setStatus("UNKNOWNON");
			} else if ("poweredOff".equalsIgnoreCase(oldServer.getStatus())) {
				oldServer.setStatus("UNKNOWNOFF");
			} else if ("suspended".equalsIgnoreCase(oldServer.getStatus())) {
				oldServer.setStatus("UNKNOWNSUSPEND");
			} else {
				oldServer.setStatus(hostStatus);
			}
			oldServer.setManagerIp(managerIp);
		} else if ("poweredOn".equalsIgnoreCase(oldServer.getStatus())) {
			oldServer.setStatus(VMStatus.RUNNING.name());
		} else if ("poweredOff".equalsIgnoreCase(oldServer.getStatus())) {
			oldServer.setStatus(VMStatus.STOPPED.name());
			oldServer.setManagerIp(managerIp);
		} else if ("suspended".equalsIgnoreCase(oldServer.getStatus())) {
			oldServer.setStatus(VMStatus.SUSPENDED.name());
			oldServer.setManagerIp(managerIp);
		} else {
			oldServer.setStatus(VMStatus.EXCEPTION.name());
		}
		cloudServerDao.update(oldServer);
		Long serverId = oldServer.getId();
		// 同步该虚拟机和存储的关系
		mergeStoreHost(vendorId, serverId, "VM", newServer.getStores(), storeMap);
		// 同步该虚拟机和网络的关系
		mergeNetworkHost(vendorId, serverId, "VM", newServer.getNetworks(), networkMap, groupMap);
		// 同步该虚拟机下的网卡
		List<NetworkCard> oldCards = networkCardDao.listByHost(serverId, "VM");
		syncNetworkCard(oldCards, newServer.getNetcards(), vendorId, serverId, userId, "VM", groupMap);
		// 同步该虚拟机下的快照
		List<Snapshot> shots = snapshotDao.listByVMid(serverId);
		syncSnapshot(shots, newServer.getSnapshots(), vendorId, serverId, userId);
	}

	/**
	 * 添加虚拟机及之下的快照信息
	 * 
	 * @param storeMap
	 * @param newServers
	 * @param vendorId
	 * @param hostId
	 * @param userId
	 * @throws Exception
	 */
	public void addServerCascade(Map<String, Long> storeMap, CloudServer cloudServer, Long vendorId, Long hostId,
			Long userId, String status, Map<String, Long> networkMap, Map<String, PortGroup> groupMap)
					throws Exception {
		cloudServer.preSave(userId, userId, vendorId, hostId, null);
		if ("UNKNOWN".equals(status)) {
			cloudServer.setStatus(status);
		} else if (cloudServer.getStatus().equalsIgnoreCase("poweredOn")) {
			cloudServer.setStatus(VMStatus.RUNNING.name());
		} else if (cloudServer.getStatus().equalsIgnoreCase("poweredOff")) {
			cloudServer.setStatus(VMStatus.STOPPED.name());
		} else {
			cloudServer.setStatus(VMStatus.EXCEPTION.name());
		}
		cloudServer.setName(URLDecoder.decode(cloudServer.getName(), "utf-8"));
		cloudServerDao.save(cloudServer);
		Long serverId = cloudServer.getId();
		// 同步存储
		addStore(vendorId, serverId, userId, "VM", cloudServer.getStores(), storeMap);
		// 同步网络
		addNetwork(vendorId, serverId, userId, "VM", cloudServer.getNetworks(), networkMap, groupMap);
		// 同步网卡
		addCard(vendorId, serverId, userId, "VM", cloudServer.getNetcards(), groupMap);
		// 同步快照
		addSnapshot(vendorId, serverId, userId, cloudServer.getSnapshots());
	}

	public void addStore(Long vendorId, Long hostId, Long userId, String category, List<String> stores,
			Map<String, Long> storeMap) throws Exception {
		if (!ListTool.isEmpty(stores)) {
			for (String store : stores) {
				if (storeMap.containsKey(store)) {
					storeHostDao.save(new StoreHost(storeMap.get(store), hostId, vendorId, category));
				}
			}
		}
	}

	public void addNetwork(Long vendorId, Long hostId, Long userId, String category, List<String> networks,
			Map<String, Long> networkMap, Map<String, PortGroup> groupMap) throws Exception {
		if (!ListTool.isEmpty(networks)) {
			Map<Long, String> idMap = Maps.newHashMap();
			for (String network : networks) {
				if (networkMap.containsKey(network)) {
					networkHostDao.save(new NetworkHost(networkMap.get(network), hostId, vendorId, category));
				} else if (groupMap.containsKey(network) && !idMap.containsKey(groupMap.get(network).getNetworkId())) {
					idMap.put(groupMap.get(network).getNetworkId(), network);
					networkHostDao
							.save(new NetworkHost(groupMap.get(network).getNetworkId(), hostId, vendorId, category));
				}
			}
		}
	}

	public void addCard(Long vendorId, Long hostId, Long userId, String category, List<NetworkCard> cards,
			Map<String, PortGroup> groupMap) throws Exception {
		if (!ListTool.isEmpty(cards)) {
			for (NetworkCard card : cards) {
				if (groupMap.containsKey(card.getName())) {
					card.setName(groupMap.get(card.getName()).getName());
				}
				card.preSave(userId, userId, vendorId, hostId, category);
				networkCardDao.save(card);
			}
		}
	}

	public void addSnapshot(Long vendorId, Long serverId, Long userId, List<Snapshot> snapshots) throws Exception {
		if (!ListTool.isEmpty(snapshots)) {
			for (Snapshot snapshot : snapshots) {
				snapshot.preSave(userId, userId, vendorId, serverId);
				snapshotDao.save(snapshot);
			}
		}
	}

	/**
	 * 同步网卡
	 * 
	 * @param oldCards
	 * @param newCards
	 * @param vendorId
	 * @param hostId
	 * @param userId
	 * @throws Exception
	 */
	public void syncNetworkCard(List<NetworkCard> oldCards, List<NetworkCard> newCards, Long vendorId, Long hostId,
			Long userId, String category, Map<String, PortGroup> groupMap) throws Exception {
		if (ListTool.isEmpty(oldCards) && !ListTool.isEmpty(newCards)) {// 数据库不存在，该虚拟机下存在快照，则全部新增
			// 新增
			for (NetworkCard card : newCards) {
				if (groupMap.containsKey(card.getName())) {
					card.setName(groupMap.get(card.getName()).getName());
				}
				card.preSave(userId, userId, vendorId, hostId, category);
				networkCardDao.save(card);
			}
		} else if (!ListTool.isEmpty(oldCards) && !ListTool.isEmpty(newCards)) {// 数据库存在，该虚拟机下存在快照，则全部新增更新或删除
			Map<String, NetworkCard> oldShot = Maps.newHashMap();
			for (NetworkCard card : oldCards) {
				oldShot.put(card.getMac(), card);
			}
			// 同步网卡更新新增
			for (NetworkCard card : newCards) {
				if (oldShot.containsKey(card.getMac())) {
					NetworkCard netCard = oldShot.get(card.getMac());
					if (groupMap.containsKey(card.getName())) {
						netCard.setName(groupMap.get(card.getName()).getName());
					}
					netCard.setMenderId(userId);
					netCard.setVendorId(vendorId);
					netCard.setLabel(card.getLabel());
					netCard.setUsed(card.getUsed());
					networkCardDao.update(netCard);
					// 移除存在更新的网卡
					oldShot.remove(card.getMac());
				} else {
					if (groupMap.containsKey(card.getName())) {
						card.setName(groupMap.get(card.getName()).getName());
					}
					card.preSave(userId, userId, vendorId, hostId, category);
					networkCardDao.save(card);
				}
			}
			// 同步删除不存在的快照
			Iterator<NetworkCard> cards = oldShot.values().iterator();
			while (cards.hasNext()) {
				networkCardDao.delete(cards.next().getId(), userId);
			}
		} else if (!ListTool.isEmpty(oldCards) && ListTool.isEmpty(newCards)) {// 数据库存在，该虚拟机不存在快照，则全部删除
			networkCardDao.deleteByHost(hostId, category, userId);
		}
	}

	/**
	 * 同步快照
	 * 
	 * @param oldShots
	 * @param newShots
	 * @param vendorId
	 * @param vmId
	 * @param userId
	 * @throws Exception
	 */
	public void syncSnapshot(List<Snapshot> oldShots, List<Snapshot> newShots, Long vendorId, Long vmId, Long userId)
			throws Exception {
		if (ListTool.isEmpty(oldShots) && !ListTool.isEmpty(newShots)) {// 数据库不存在，该虚拟机下存在快照，则全部新增
			// 新增
			for (Snapshot snapshot : newShots) {
				snapshot.preSave(userId, userId, vendorId, vmId);
				snapshotDao.save(snapshot);
			}
		} else if (!ListTool.isEmpty(oldShots) && !ListTool.isEmpty(newShots)) {// 数据库存在，该虚拟机下存在快照，则全部新增更新或删除
			Map<String, Snapshot> oldShot = Maps.newHashMap();
			for (Snapshot shot : oldShots) {
				oldShot.put(shot.getSnapshotId() + shot.getSnapshotVal(), shot);
			}
			// 同步快照更新新增
			for (Snapshot snapshot : newShots) {
				if (oldShot.containsKey(snapshot.getSnapshotId() + snapshot.getSnapshotVal())) {
					Snapshot shot = oldShot.get(snapshot.getSnapshotId() + snapshot.getSnapshotVal());
					SnapshotBean bean = new SnapshotBean();
					BeanUtils.copyProperties(snapshot, bean);
					BeanUtils.copyProperties(bean, shot);
					shot.setMenderId(userId);
					shot.setVendorId(vendorId);
					shot.setVmId(vmId);
					snapshotDao.update(shot);
					// 移除存在更新的快照
					oldShot.remove(snapshot.getSnapshotId() + snapshot.getSnapshotVal());
				} else {
					snapshot.preSave(userId, userId, vendorId, vmId);
					snapshotDao.save(snapshot);
				}
			}
			// 同步删除不存在的快照
			Iterator<Snapshot> shots = oldShot.values().iterator();
			while (shots.hasNext()) {
				snapshotDao.remove(shots.next().getId(), userId);
			}
		} else if (!ListTool.isEmpty(oldShots) && ListTool.isEmpty(newShots)) {// 数据库存在，该虚拟机不存在快照，则全部删除
			snapshotDao.removeByVm(vmId, userId);
		}
	}

}
